package com.wan37.logic;

import com.wan37.common.xml.XMLUtils;
import com.wan37.logic.chat.cache.ChatCache;
import com.wan37.logic.chat.domain.vo.ChatVO;
import com.wan37.logic.chat.service.WorldChatService;
import com.wan37.logic.component.LogicWorkerHandlerCenter;
import com.wan37.logic.db.AsynDBManager;
import com.wan37.logic.guild.cache.GuildCache;
import com.wan37.logic.guild.domain.vo.GuildUserVO;
import com.wan37.logic.guild.domain.vo.GuildVO;
import com.wan37.logic.guild.domain.vo.GuildWarehouseVO;
import com.wan37.logic.guild.service.GuildService;
import com.wan37.logic.guild.service.GuildUserService;
import com.wan37.logic.guild.service.GuildWarehouseService;
import com.wan37.logic.shop.Shop;
import com.wan37.logic.shop.cache.CommodityServiceCache;
import com.wan37.logic.shop.cache.ShopCache;
import com.wan37.logic.shop.dao.CommodityDao;
import com.wan37.logic.shop.domain.entity.CommodityDO;
import com.wan37.logic.shop.domain.vo.CommodityConfigVO;
import com.wan37.logic.shop.domain.vo.CommodityVO;
import com.wan37.logic.shop.domain.vo.ShopVO;
import com.wan37.logic.shop.service.CommodityService;
import com.wan37.logic.shop.service.ShopService;
import com.wan37.logic.task.cache.TaskCache;
import com.wan37.logic.task.domain.vo.TaskConfigVO;
import com.wan37.logic.tradingshop.cache.TradingShopCache;
import com.wan37.logic.tradingshop.domain.vo.TradingShopRecordVO;
import com.wan37.logic.tradingshop.domain.vo.TradingShopVO;
import com.wan37.logic.tradingshop.handler.AuctionResultHandler;
import com.wan37.logic.tradingshop.service.TradingShopRecordService;
import com.wan37.logic.tradingshop.service.TradingShopService;
import com.wan37.logic.utils.*;
import com.wan37.protobuf.constant.CommonBase;
import com.wan37.logic.domain.vo.*;
import com.wan37.logic.global.reference.SpringContextHolder;
import com.wan37.logic.listener.ListenerManager;
import com.wan37.logic.server.*;
import com.wan37.logic.service.cache.*;
import com.wan37.protobuf.constant.AllRoleLabel;
import com.wan37.protobuf.constant.TradingShopLabel;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author : luoyong
 * @date : 2020-05-28 09:34
 **/
public class LogicStarter {
    private final static Logger logger = LoggerFactory.getLogger(LogicStarter.class);

    /**
     * logicServer端口号
     */
    private static int logicServerPort;
    /**
     * 工作线程的数量
     */
    public static int workerNum;

    private MonsterServiceCache monsterServiceCache;
    private SkillServiceCache skillServiceCache;
    private NpcServiceCache npcServiceCache;
    private SceneServiceCache sceneServiceCache;
    private WeaponryServiceCache weaponryServiceCache;
    private ItemServiceCache itemServiceCache;
    private RoleLevelUtil roleLevelUtil;
    private SkillLevelUtil skillLevelUtil;
    private XmlUtil xmlUtil;
    private WeaponryLevelUtil weaponryLevelUtil;
    private CommodityServiceCache commodityServiceCache;
    private AsynDBManager asynDBManager;
    private WorldChatService worldChatService;
    private ChatCache chatCache;
    private GuildCache guildCache;
    private GuildService guildService;
    private GuildUserService guildUserService;
    private GuildWarehouseService guildWarehouseService;
    private UserServiceCache userServiceCache;
    private TradingShopCache tradingShopCache;
    private TradingShopService tradingShopService;
    private TradingShopRecordService tradingShopRecordService;
    private LogicWorkerHandlerCenter logicWorkerHandlerCenter;
    private DelayDequeThreadPollUtil delayDequeThreadPollUtil;
    private TaskCache taskCache;
    private ShopService shopService;
    private CommodityService commodityService;
    private ShopCache shopCache;

    public static void main(String[] args) {
        new LogicStarter().configAndStart();
    }

    /**
     * 配置和启动服务.
     */
    public void configAndStart() {
        //读取配置文件
        Element logic = XMLUtils.parseXmlFile("logic/logic-config.xml");
        assert logic != null;
        Element logicServerElement = logic.element("logicServer");
        logicServerPort = Integer.parseInt(logicServerElement.attributeValue("port").trim());
        workerNum = Integer.parseInt(logicServerElement.attributeValue("workerNum").trim());
        logger.info("logicServerPort: {}, workerNum: {}", logicServerPort, workerNum);

        //读取spring
        new ClassPathXmlApplicationContext("spring/logic-spring-config.xml");

        this.monsterServiceCache = SpringContextHolder.getBean("monsterServiceCache");
        this.skillServiceCache = SpringContextHolder.getBean("skillServiceCache");
        this.npcServiceCache = SpringContextHolder.getBean("npcServiceCache");
        this.sceneServiceCache = SpringContextHolder.getBean("sceneServiceCache");
        this.weaponryServiceCache = SpringContextHolder.getBean("weaponryServiceCache");
        this.itemServiceCache = SpringContextHolder.getBean("itemServiceCache");
        this.roleLevelUtil = SpringContextHolder.getBean("roleLevelUtil");
        this.skillLevelUtil = SpringContextHolder.getBean("skillLevelUtil");
        this.xmlUtil = SpringContextHolder.getBean("xmlUtil");
        this.weaponryLevelUtil = SpringContextHolder.getBean("weaponryLevelUtil");
        this.commodityServiceCache = SpringContextHolder.getBean("commodityServiceCache");
        this.asynDBManager = SpringContextHolder.getBean("asynDBManager");
        this.worldChatService = SpringContextHolder.getBean("worldChatService");
        this.chatCache = SpringContextHolder.getBean("chatCache");
        this.guildCache = SpringContextHolder.getBean("guildCache");
        this.guildService = SpringContextHolder.getBean("guildService");
        this.guildUserService = SpringContextHolder.getBean("guildUserService");
        this.guildWarehouseService = SpringContextHolder.getBean("guildWarehouseService");
        this.userServiceCache = SpringContextHolder.getBean("userServiceCache");
        this.tradingShopCache = SpringContextHolder.getBean("tradingShopCache");
        this.tradingShopService = SpringContextHolder.getBean("tradingShopService");
        this.tradingShopRecordService = SpringContextHolder.getBean("tradingShopRecordService");
        this.logicWorkerHandlerCenter = SpringContextHolder.getBean("logicWorkerHandlerCenter");
        this.delayDequeThreadPollUtil = SpringContextHolder.getBean("delayDequeThreadPollUtil");
        this.taskCache = SpringContextHolder.getBean("taskCache");
        this.commodityService = SpringContextHolder.getBean("commodityService");
        this.shopCache = SpringContextHolder.getBean("shopCache");
        this.shopService = SpringContextHolder.getBean("shopService");
        //启动异步数据库线程处理线程池
        asynDBManager.startWorks();
        //配置技能集合
        readSkillXml("logic/logic-skill.xml");

        //配置怪物集合
        readMonsterXml("logic/logic-monster.xml");

        //配置NPC集合
        readNpcXml("logic/logic-npc.xml");

        //初始化配置武器集合
        readWeaponryXml("logic/logic-weaponry.xml");

        //初始化物品集合
        readItemXml("logic/logic-item.xml");

        //配置用户角色等级数值集合
        roleLevelUtil.readLevelXml("logic/logic-level.xml");

        //配置技能等级加强数值
        skillLevelUtil.readSkillLevelXml("logic/logic-skill-level.xml");
        //配置装备等级数值
        weaponryLevelUtil.readWeaponryLevelXml("logic/logic-weaponry-level.xml");
        //配置boss技能
        readBossSkillXml("logic/logic-boss-skill.xml");
        //配置商城信息
        readShopXml("logic/logic-shop.xml");

        //配置任务系统信息
        readTaskXml("logic/logic-task.xml");
        //初始化公会数据
        loadGuildData();
        //初始化拍卖行数据
        loadTradingShopData();
        //初始化世界聊天记录数据
        loadAllWorldChat();

        //配置logicServer
        LogicServer logicServer = (LogicServer) SpringContextHolder.getApplicationContext().getBean("logicServer");
        logicServer.setPort(logicServerPort);

        //初始化地图信息
        sceneServiceCache.init();

        //事件驱动模型管理初始化
        ListenerManager.getInstance().init();

        //启动LogicServer
        new Thread(logicServer).start();

    }



    /**
     * 任务系统配置读取
     * @param path
     */
    private void readTaskXml(String path) {
        List<TaskConfigVO> taskConfigVOList = xmlUtil.getXmlFileValues(path, TaskConfigVO.class);
        for (TaskConfigVO taskConfigVO : taskConfigVOList){
            taskCache.getTaskId2TaskConfig().put(taskConfigVO.getTaskId(), taskConfigVO);
        }
        logger.info("任务系统配置初始化完成");
    }

    private void loadTradingShopData() {
        List<TradingShopVO> tradingShopVOList = tradingShopService.getAll();
        if (tradingShopVOList == null){
            return;
        }
        for (TradingShopVO tradingShopVO : tradingShopVOList){

            TradingShopCache.TradingShopIn tradingShopIn = tradingShopCache.new TradingShopIn();
            tradingShopIn.setTradingShopVO(tradingShopVO);
            if (tradingShopRecordService.findByTradingShopId(tradingShopVO.getTradingShopId()) != null){
                for (TradingShopRecordVO tradingShopRecordVO :
                        tradingShopRecordService.findByTradingShopId(tradingShopVO.getTradingShopId())){
                    tradingShopIn.getTradingShopRecordVOList()
                            .add(tradingShopRecordVO);
                }
            }
            if (tradingShopVO.getTradingShopType() == TradingShopLabel.AUCTION){
                long time = System.currentTimeMillis() - tradingShopVO.getCreateTime();
                if (time >= TradingShopLabel.AUCTION_TIME * 1000){
                    logicWorkerHandlerCenter.distributeWork(tradingShopVO.getTradingShopId(),
                            new AuctionResultHandler(tradingShopVO.getTradingShopId()));
                }else {
                    delayDequeThreadPollUtil.updateTimeSchedule(time / 1000, null,
                            tradingShopVO.getTradingShopId(), new AuctionResultHandler(tradingShopVO.getTradingShopId()));
                }
            }
        }
        logger.info("拍卖行数据初始化完成！！！！");
    }

    private void loadGuildData() {
        List<GuildVO> guildVOList = guildService.getAll();
        if (guildVOList == null){
            return;
        }
        for (GuildVO guildVO : guildVOList){
            GuildCache.GuildIn guildIn = guildCache.new GuildIn();
            guildIn.setGuildVO(guildVO);
            for (GuildUserVO guildUserVO : guildUserService.getGuildUserByGuildId(guildVO.getGuildId())){
                guildIn.getGuildUserVOList().add(guildUserVO);
            }
            for (GuildWarehouseVO guildWarehouseVO :
                    guildWarehouseService.getGuildWarehouseByGuildId(guildVO.getGuildId())){
                guildIn.getGuildWarehouseVOList().add(guildWarehouseVO);
            }
            guildCache.getGuildInMap().put(guildVO.getGuildId(), guildIn);
        }
        logger.info("公会数据初始化完成！！！！");
    }

    /**
     * 初始化怪物集合
     *
     * @param path
     */
    private void readMonsterXml(String path) {
        List<MonsterVO> monsterVOList = xmlUtil.getXmlFileValues(path, MonsterVO.class);
        for (MonsterVO monsterVO : monsterVOList) {
            monsterVO.setLabel(AllRoleLabel.MONSTER);
            MonsterServiceCache.Monster monster = monsterServiceCache.new Monster();
            monster.setBaseMp(monsterVO.getNumberMap().get(CommonBase.MP));
            monster.setMonsterVO(monsterVO);
            monster.setSkillVOMap(new ConcurrentHashMap<>());
            monsterServiceCache.getMonsterServiceMap().put(monsterVO.getAllRoleId(), monster);

        }
        logger.info("怪物配置初始化完成！！！！");
    }

    private void readNpcXml(String path) {
        List<NpcVO> npcVOList = xmlUtil.getXmlFileValues(path, NpcVO.class);
        for (NpcVO npcVO : npcVOList) {
            npcVO.setLabel(AllRoleLabel.NPC);
            NpcServiceCache.Npc npc = npcServiceCache.new Npc();
            npc.setNpcVO(npcVO);
            npcServiceCache.getNpcIdToNpc().put(npcVO.getAllRoleId(), npc);
        }
        logger.info("NPC配置初始化完成！！！！！！！！！");
    }


    /**
     * 初始化技能集合
     *
     * @param path
     */
    public void readSkillXml(String path) {
        List<SkillVO> skillVOList = xmlUtil.getXmlFileValues(path, SkillVO.class);
        for (SkillVO skillVO : skillVOList) {
            SkillServiceCache.Skill skill = skillServiceCache.new Skill();
            skill.setSkillVO(skillVO);
            skillServiceCache.getSkillServiceMap().put(skillVO.getId(), skill);
        }
        logger.info("技能Map集合配置完成！！！！！");
    }

    public void readWeaponryXml(String path) {
        List<WeaponryVO> weaponryVOList = xmlUtil.getXmlFileValues(path, WeaponryVO.class);
        for (WeaponryVO weaponryVO : weaponryVOList) {
            WeaponryServiceCache.Weaponry weaponry = weaponryServiceCache.new Weaponry();
            weaponry.setWeaponryVO(weaponryVO);
            weaponryServiceCache.getWeaponryServiceMap().put(weaponryVO.getBackpackId(), weaponry);
        }
        logger.info("武器Map集合配置完成！！！！！");
    }

    public void readItemXml(String path) {
        List<ItemVO> itemVOList = xmlUtil.getXmlFileValues(path, ItemVO.class);
        for (ItemVO itemVO : itemVOList) {
            ItemServiceCache.Item item = itemServiceCache.new Item();
            item.setItemVO(itemVO);
            itemServiceCache.getItemServiceMap().put(itemVO.getBackpackId(), item);
        }
        logger.info("物品Map集合配置完成！！！！！");
    }

    public void readBossSkillXml(String path) {
        List<BossSkillVO> bossSkillVOList = xmlUtil.getXmlFileValues(path, BossSkillVO.class);
        bossSkillVOList.forEach(bossSkillVO -> {
            monsterServiceCache.getMonsterServiceMap().get(bossSkillVO.getAllRoleId())
                    .getSkillVOMap().put(bossSkillVO.getSkillId(),
                    skillServiceCache.getSkillServiceMap().get(bossSkillVO.getSkillId()).getSkillVO());
        });
        logger.info("boss技能Map集合配置完成！！！！！");
    }

    /**
     * 先读取商城配置信息，然后获取数据库中商城信息，判断商城中是否已经存在对应配置
     * 如果已经存在就将刷新时间戳取出来，写入缓存
     * 如果配置不存在这个商城信息，则保存商城信息到数据库
     * @param path
     */
    private void readShopXml(String path) {
        List<ShopVO> shopVOList = xmlUtil.getXmlFileValues(path, ShopVO.class);
        for (ShopVO shopVO : shopVOList){
            shopVO.setRefreshTimeDay(System.currentTimeMillis() / (24 * 3600000));
            ShopCache.ShopIn shopIn = shopCache.new ShopIn();
            shopIn.setShopVO(shopVO);
            shopCache.getShopInMap().put(shopVO.getShopId(), shopIn);
        }
        //初始化商城物品配置信息
        readCommodityXml("logic/logic-commodity.xml");
        List<ShopVO> shopVOList1 = shopService.getAll();
        //说明数据库没有保存商城，需要全量保存
        if (shopVOList1 == null){
            for (ShopVO shopVO : shopVOList){
                asynDBManager.distributeWork(shopVO.getShopId(), ()->shopService.save(shopVO));
            }
            for (CommodityServiceCache.CommodityIn commodityIn : commodityServiceCache.getCommodityInMap().values()){
                CommodityVO commodityVO = new CommodityVO(commodityIn.getCommodityConfigVO());
                shopCache.getShopInMap().get(commodityVO.getShopId())
                        .getCommodityVOMap().put(commodityVO.getCommodityId(), commodityVO);
                asynDBManager.distributeWork(commodityVO.getShopId(), ()->commodityService.save(commodityVO));
            }
        }else {
            for (ShopVO shopVO : shopVOList){
                //为了判断后面是否有新添加的商城类型信息，需要做保存操作
                boolean flag = true;
                for (ShopVO shopVO1 : shopVOList1){
                    //数据库中的shop数据中有缓存配置中加载进来的商城数据，进行缓存中时间戳更新，替换为数据库中更新时间戳
                    if (shopVO.getShopId().equals(shopVO1.getShopId())){
                        shopCache.getShopInMap().get(shopVO1.getShopId()).getShopVO().setRefreshTimeDay(shopVO1.getRefreshTimeDay());
                        //将所有的物品数据进行遍历，找到这个商城的物品
                        for (CommodityServiceCache.CommodityIn commodityIn : commodityServiceCache.getCommodityInMap().values()){
                            if (shopVO.getShopId().equals(commodityIn.getCommodityConfigVO().getShopId())){
                                CommodityVO commodityVO = new CommodityVO(commodityIn.getCommodityConfigVO());
                                CommodityVO commodityVO1 = commodityService
                                        .findCommodityByShopIdAndCommodityId(commodityVO);
                                //访问数据库，查看数据库对应的数据是否为空，为空则进行数据插入操作，数据缓存用配置信息修改，不为空则用查到的数据更新缓存。
                                if (commodityVO1 == null){
                                    asynDBManager.distributeWork(shopVO.getShopId(), ()->commodityService.save(commodityVO));
                                    shopCache.getShopInMap().get(commodityVO.getShopId())
                                            .getCommodityVOMap().put(commodityVO.getCommodityId(), commodityVO);
                                }else {
                                    shopCache.getShopInMap().get(commodityVO.getShopId())
                                            .getCommodityVOMap().put(commodityVO.getCommodityId(), commodityVO1);
                                }
                            }
                        }
                        flag = false;
                        break;
                    }
                }
                //为true，则说明这个商城第一次加载，进行商城保存操作以及对应物品保存和加载到缓存操作
                if (flag){
                    asynDBManager.distributeWork(shopVO.getShopId(), ()->shopService.save(shopVO));
                    for (CommodityServiceCache.CommodityIn commodityIn : commodityServiceCache.getCommodityInMap().values()){
                        if (shopVO.getShopId().equals(commodityIn.getCommodityConfigVO().getShopId())){
                            CommodityVO commodityVO = new CommodityVO(commodityIn.getCommodityConfigVO());
                            shopCache.getShopInMap().get(commodityVO.getShopId())
                                    .getCommodityVOMap().put(commodityVO.getCommodityId(), commodityVO);
                            asynDBManager.distributeWork(commodityVO.getShopId(), ()->commodityService.save(commodityVO));
                        }
                    }
                }
            }
        }
    }

    /**
     * 读取商城对应商品信息
     * @param path
     */
    private void readCommodityXml(String path) {
        List<CommodityConfigVO> commodityConfigVOList = xmlUtil.getXmlFileValues(path, CommodityConfigVO.class);
        commodityConfigVOList.forEach(commodityVO -> {
            CommodityServiceCache.CommodityIn commodityIn = commodityServiceCache.new CommodityIn();
            commodityIn.setCommodityConfigVO(commodityVO);
            commodityServiceCache.getCommodityInMap().put(commodityVO.getCommodityId(), commodityIn);
        });
        logger.info("商城信息初始化成功！");
    }

    /**
     * 从数据库中获取世界聊天消息记录
     */
    private void loadAllWorldChat() {
        List<ChatVO> chatVOList = worldChatService.getAllWorldChatDO();
        chatCache.getWorldChatVOList().addAll(chatVOList);
    }
}
